package org.xiaoyu.feign.core;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import org.springframework.util.StringUtils;

import feign.Client;
import feign.Request;
import feign.Request.Options;
import feign.Response;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.RequestBody;

public class FeignOkHttp3Client implements Client {

	private final OkHttpClient client = new OkHttpClient();

	private final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
	/**
	 * 是否采用url服务
	 */
	private boolean localService = true;

	public FeignOkHttp3Client() {
	}
	
	public FeignOkHttp3Client(boolean localService) {
		this.localService = localService;
	}

	@Override
	public Response execute(Request request, Options options) throws IOException {
		String url = request.url();
		if(!localService) {
			URI asUri = URI.create(request.url());
			String clientName = asUri.getHost();
			List<String> urls = FeignZookeeper.serviceAndUrl.get(clientName);
			if(urls != null && urls.size() > 0) {
				Random random = new Random();
				int randomPos = random.nextInt(urls.size());
				url = url.replaceFirst(clientName, urls.get(randomPos));
			}else {
				return Response.builder().status(404).build();
			}
		}
		if(!url.startsWith("http")) {
			url = "http://" + url;
		}
		client.newBuilder().connectTimeout(options.connectTimeoutMillis(), TimeUnit.MILLISECONDS)
				.readTimeout(options.readTimeoutMillis(), TimeUnit.MILLISECONDS)
				.followRedirects(options.isFollowRedirects());

		okhttp3.Request.Builder reBulid = new okhttp3.Request.Builder().url(url);
		if (!StringUtils.isEmpty(request.body()) && !request.method().equals("GET")) {
			RequestBody body = RequestBody.create(JSON, request.body());
			reBulid.method(request.method(), body);
		} else {
			reBulid.method(request.method(), null);
		}
		boolean hasAcceptHeader = false;
		for (String field : request.headers().keySet()) {
			if (field.equalsIgnoreCase("Accept")) {
				hasAcceptHeader = true;
			}
			for (String value : request.headers().get(field)) {
				reBulid.addHeader(field, value);
			}
		}

		if (!hasAcceptHeader) {
			reBulid.addHeader("Accept", "*/*");
		}
		okhttp3.Request re = reBulid.build();
		okhttp3.Response response = client.newCall(re).execute();
		int status = response.code();
		InputStream stream = response.body().byteStream();
		Map<String, Collection<String>> headers = new LinkedHashMap<String, Collection<String>>();
		for (Map.Entry<String, List<String>> field : response.headers().toMultimap().entrySet()) {
			if (field.getKey() != null) {
				headers.put(field.getKey(), field.getValue());
			}
		}
		return Response.builder().status(status).reason(response.message()).headers(headers)
				.body(stream, (int) response.body().contentLength()).build();
	}

}
